//
// Created by 常磊 on 2022/4/5.
//

import Foundation
import Alamofire

// MARK: - Default

extension DioDataRequest {
    @discardableResult
    public func response(queue: DispatchQueue = .main, completionHandler: @escaping (DioDataResponse<Data?>) -> Void) -> Self {
        dataCore.response(queue: queue) { (response: AFDataResponse<Data?>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
    
    @discardableResult
    public func response<Serializer: DataResponseSerializerProtocol>(
        queue: DispatchQueue = .main,
        responseSerializer: Serializer,
        completionHandler: @escaping (DioDataResponse<Serializer.SerializedObject>) -> Void
    ) -> Self {
        dataCore.response(queue: queue, responseSerializer: responseSerializer) { (response: AFDataResponse<Serializer.SerializedObject>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
    
    @discardableResult
    public func response<Serializer: ResponseSerializer>(
        queue: DispatchQueue = .main,
        responseSerializer: Serializer,
        completionHandler: @escaping (DioDataResponse<Serializer.SerializedObject>) -> Void
    ) -> Self {
        dataCore.response(queue: queue, responseSerializer: responseSerializer) { (response: AFDataResponse<Serializer.SerializedObject>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
}

extension DioDownloadRequest {
    @discardableResult
    public func response(queue: DispatchQueue = .main, completionHandler: @escaping (DioDownloadResponse<URL?>) -> Void) -> Self {
        dataCore.response(queue: queue) { (response: AFDownloadResponse<URL?>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
    
    @discardableResult
    public func response<Serializer: DownloadResponseSerializerProtocol>(
        queue: DispatchQueue = .main,
        responseSerializer: Serializer,
        completionHandler: @escaping (DioDownloadResponse<Serializer.SerializedObject>) -> Void
    ) -> Self {
        dataCore.response(queue: queue, responseSerializer: responseSerializer) { (response: AFDownloadResponse<Serializer.SerializedObject>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
    
    @discardableResult
    public func response<Serializer: ResponseSerializer>(
        queue: DispatchQueue = .main,
        responseSerializer: Serializer,
        completionHandler: @escaping (DioDownloadResponse<Serializer.SerializedObject>) -> Void
    ) -> Self {
        dataCore.response(queue: queue, responseSerializer: responseSerializer) { (response: AFDownloadResponse<Serializer.SerializedObject>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
}

// MARK: - URL

extension DioDownloadRequest {
    @discardableResult
    public func responseURL(queue: DispatchQueue = .main, completionHandler: @escaping (DioDownloadResponse<URL>) -> Void) -> Self {
        response(queue: queue, responseSerializer: URLResponseSerializer(), completionHandler: completionHandler)
    }
}

// MARK: - Data

extension DioDataRequest {
    @discardableResult
    public func responseData(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDataResponse<Data>) -> Void
    ) -> Self {
        response(
            queue: queue,
            responseSerializer: DataResponseSerializer(
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ),
            completionHandler: completionHandler
        )
    }
}

extension DioDownloadRequest {
    @discardableResult
    public func responseData(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDownloadResponse<Data>) -> Void
    ) -> Self {
        response(
            queue: queue,
            responseSerializer: DataResponseSerializer(
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ),
            completionHandler: completionHandler
        )
    }
}

// MARK: - String

extension DioDataRequest {
    @discardableResult
    public func responseString(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
        encoding: String.Encoding? = nil,
        emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDataResponse<String>) -> Void
    ) -> Self {
        response(
            queue: queue,
            responseSerializer: StringResponseSerializer(
                dataPreprocessor: dataPreprocessor,
                encoding: encoding,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ),
            completionHandler: completionHandler
        )
    }
}

extension DioDownloadRequest {
    @discardableResult
    public func responseString(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
        encoding: String.Encoding? = nil,
        emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDownloadResponse<String>) -> Void
    ) -> Self {
        response(
            queue: queue,
            responseSerializer: StringResponseSerializer(
                dataPreprocessor: dataPreprocessor,
                encoding: encoding,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ),
            completionHandler: completionHandler
        )
    }
}

// MARK: - JSON

extension DioDataRequest {
    @available(*, deprecated, message: "responseJSON deprecated and will be removed in Dio 6. Use responseDecodable instead.")
    @discardableResult
    public func responseJSON(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
        options: JSONSerialization.ReadingOptions = .allowFragments,
        completionHandler: @escaping (DioDataResponse<Any>) -> Void
    ) -> Self {
        response(
            queue: queue,
            responseSerializer: JSONResponseSerializer(
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods,
                options: options
            ),
            completionHandler: completionHandler
        )
    }
}

extension DioDownloadRequest {
    @available(*, deprecated, message: "responseJSON deprecated and will be removed in Dio 6. Use responseDecodable instead.")
    @discardableResult
    public func responseJSON(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
        options: JSONSerialization.ReadingOptions = .allowFragments,
        completionHandler: @escaping (DioDownloadResponse<Any>) -> Void
    ) -> Self {
        response(
            queue: queue,
            responseSerializer: JSONResponseSerializer(
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods,
                options: options
            ),
            completionHandler: completionHandler
        )
    }
}

// MARK: - Decodable

extension DioDataRequest {
    @discardableResult
    public func responseDecodable<T: Decodable>(
        of type: T.Type = T.self,
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
        decoder: DataDecoder = JSONDecoder(),
        emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDataResponse<T>) -> Void
    ) -> Self {
        dataCore.responseDecodable(
            of: type,
            queue: queue,
            dataPreprocessor: dataPreprocessor,
            decoder: decoder,
            emptyResponseCodes: emptyResponseCodes,
            emptyRequestMethods: emptyRequestMethods
        ) { (response: AFDataResponse<T>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
}

extension DioDownloadRequest {
    @discardableResult
    public func responseDecodable<T: Decodable>(
        of type: T.Type = T.self,
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
        decoder: DataDecoder = JSONDecoder(),
        emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDownloadResponse<T>) -> Void
    ) -> Self {
        dataCore.responseDecodable(
            of: type,
            queue: queue,
            dataPreprocessor: dataPreprocessor,
            decoder: decoder,
            emptyResponseCodes: emptyResponseCodes,
            emptyRequestMethods: emptyRequestMethods
        ) { (response: AFDownloadResponse<T>) in
            completionHandler(response.mapError({ error in error }))
        }
        return self
    }
}

extension DioDataStreamRequest {
    @discardableResult
    public func responseStream(on queue: DispatchQueue = .main, stream: @escaping Handler<Data, Never>) -> Self {
        dataCore.responseStream(on: queue, stream: stream)
        return self
    }
    
    @discardableResult
    public func responseStream<Serializer: DataStreamSerializer>(
        using serializer: Serializer,
        on queue: DispatchQueue = .main,
        stream: @escaping Handler<Serializer.SerializedObject, DioError>
    ) -> Self {
        dataCore.responseStream(using: serializer, on: queue, stream: stream)
        return self
    }
    
    @discardableResult
    public func responseStreamString(on queue: DispatchQueue = .main, stream: @escaping Handler<String, Never>) -> Self {
        dataCore.responseStreamString(on: queue, stream: stream)
        return self
    }
    
    @discardableResult
    public func responseStreamDecodable<T: Decodable>(
        of type: T.Type = T.self,
        on queue: DispatchQueue = .main,
        using decoder: DataDecoder = JSONDecoder(),
        preprocessor: DataPreprocessor = PassthroughPreprocessor(),
        stream: @escaping Handler<T, DioError>
    ) -> Self {
        responseStream(using: DecodableStreamSerializer<T>(decoder: decoder, dataPreprocessor: preprocessor), stream: stream)
    }
}

// MARK - async Default

#if swift(>=5.5)
extension DioDataRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func response(queue: DispatchQueue = .main) async -> DioDataResponse<Data?> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<Data?>, Never>) in
            response(queue: queue) { response in
                continuation.resume(returning: response)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func response<Serializer: DataResponseSerializerProtocol>(queue: DispatchQueue = .main, responseSerializer: Serializer) async -> DioDataResponse<Serializer.SerializedObject> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<Serializer.SerializedObject>, Never>) in
            response(queue: queue, responseSerializer: responseSerializer) { (response: DioDataResponse<Serializer.SerializedObject>) in
                continuation.resume(returning: response)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func response<Serializer: ResponseSerializer>(queue: DispatchQueue = .main, responseSerializer: Serializer) async -> DioDataResponse<Serializer.SerializedObject> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<Serializer.SerializedObject>, Never>) in
            response(queue: queue, responseSerializer: responseSerializer) { (response: DioDataResponse<Serializer.SerializedObject>) in
                continuation.resume(returning: response)
            }
        }
    }
}

extension DioDownloadRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func response(queue: DispatchQueue = .main) async -> DioDownloadResponse<URL?> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<URL?>, Never>) in
            response(queue: queue) { (response: DioDownloadResponse<Foundation.URL?>) in
                continuation.resume(returning: response)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func response<Serializer: DownloadResponseSerializerProtocol>(queue: DispatchQueue = .main, responseSerializer: Serializer) async -> DioDownloadResponse<Serializer.SerializedObject> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<Serializer.SerializedObject>, Never>) in
            response(queue: queue, responseSerializer: responseSerializer) { (response: DioDownloadResponse<Serializer.SerializedObject>) in
                continuation.resume(returning: response)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func response<Serializer: ResponseSerializer>(queue: DispatchQueue = .main, responseSerializer: Serializer) async -> DioDownloadResponse<Serializer.SerializedObject> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<Serializer.SerializedObject>, Never>) in
            response(queue: queue, responseSerializer: responseSerializer) { (response: DioDownloadResponse<Serializer.SerializedObject>) in
                continuation.resume(returning: response)
            }
        }
    }
}

// MARK: - async URL

extension DioDownloadRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseURL(queue: DispatchQueue = .main) async -> DioDownloadResponse<URL> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<URL>, Never>) in
            responseURL(queue: queue) { (response: DioDownloadResponse<Foundation.URL>) in
                continuation.resume(returning: response)
            }
        }
    }
}

// MARK: - async Data

extension DioDataRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseData(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods
    ) async -> DioDataResponse<Data> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<Data>, Never>) in
            responseData(
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ) { (response: DioDataResponse<Foundation.Data>) in
                continuation.resume(returning: response)
            }
        }
    }
}

extension DioDownloadRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseData(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods
    ) async -> DioDownloadResponse<Data> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<Data>, Never>) in
            responseData(
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ) { (response: DioDownloadResponse<Foundation.Data>) in
                continuation.resume(returning: response)
            }
        }
    }
}

// MARK: - async String

extension DioDataRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseString(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
        encoding: String.Encoding? = nil,
        emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods
    ) async -> DioDataResponse<String> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<String>, Never>) in
            responseString(
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                encoding: encoding,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ) { (response: DioDataResponse<Swift.String>) in
                continuation.resume(returning: response)
            }
        }
    }
}

extension DioDownloadRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseString(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
        encoding: String.Encoding? = nil,
        emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods
    ) async -> DioDownloadResponse<String> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<String>, Never>) in
            responseString(
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                encoding: encoding,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ) { (response: DioDownloadResponse<Swift.String>) in
                continuation.resume(returning: response)
            }
        }
    }
}

// MARK: - async JSON

extension DioDataRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    @available(*, deprecated, message: "responseJSON deprecated and will be removed in Dio 6. Use responseDecodable instead.")
    public func responseJSON(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
        options: JSONSerialization.ReadingOptions = .allowFragments
    ) async -> DioDataResponse<Any> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<Any>, Never>) in
            responseJSON(
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods,
                options: options
            ) { (response: DioDataResponse<Any>) in
                continuation.resume(returning: response)
            }
        }
    }
}

extension DioDownloadRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    @available(*, deprecated, message: "responseJSON deprecated and will be removed in Dio 6. Use responseDecodable instead.")
    public func responseJSON(
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
        emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
        options: JSONSerialization.ReadingOptions = .allowFragments
    ) async -> DioDownloadResponse<Any> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<Any>, Never>) in
            responseJSON(
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods,
                options: options
            ) { (response: DioDownloadResponse<Any>) in
                continuation.resume(returning: response)
            }
        }
    }
}

// MARK: - async Decodable

extension DioDataRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseDecodable<T: Decodable>(
        of type: T.Type = T.self,
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
        decoder: DataDecoder = JSONDecoder(),
        emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods
    ) async -> DioDataResponse<T> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDataResponse<T>, Never>) in
            responseDecodable(
                of: type,
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                decoder: decoder,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ) { (response: DioDataResponse<T>) in
                continuation.resume(returning: response)
            }
        }
    }
}

extension DioDownloadRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseDecodable<T: Decodable>(
        of type: T.Type = T.self,
        queue: DispatchQueue = .main,
        dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
        decoder: DataDecoder = JSONDecoder(),
        emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
        emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
        completionHandler: @escaping (DioDownloadResponse<T>) -> Void
    ) async -> DioDownloadResponse<T> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<DioDownloadResponse<T>, Never>) in
            responseDecodable(
                of: type,
                queue: queue,
                dataPreprocessor: dataPreprocessor,
                decoder: decoder,
                emptyResponseCodes: emptyResponseCodes,
                emptyRequestMethods: emptyRequestMethods
            ) { (response: DioDownloadResponse<T>) in
                continuation.resume(returning: response)
            }
        }
    }
}

extension DioDataStreamRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseStream(on queue: DispatchQueue = .main) async -> Stream<Data, Never> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<Stream<Data, Never>, Never>) in
            responseStream(on: queue) { (stream: Stream<Data, Never>) in
                continuation.resume(returning: stream)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseStream<Serializer: DataStreamSerializer>(using serializer: Serializer, on queue: DispatchQueue = .main) async -> Stream<Serializer.SerializedObject, DioError> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<Stream<Serializer.SerializedObject, DioError>, Never>) in
            responseStream(using: serializer, on: queue) { stream in
                continuation.resume(returning: stream)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseStreamString(on queue: DispatchQueue = .main) async -> Stream<String, Never> {
        await withCheckedCancellationContinuation { (continuation: CheckedContinuation<Stream<String, Never>, Never>) in
            responseStreamString(on: queue) { stream in
                continuation.resume(returning: stream)
            }
        }
    }
    
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    public func responseStreamDecodable<T: Decodable>(
        of type: T.Type = T.self,
        on queue: DispatchQueue = .main,
        using decoder: DataDecoder = JSONDecoder(),
        preprocessor: DataPreprocessor = PassthroughPreprocessor()
    ) async -> Stream<T, DioError> {
        await responseStream(using: DecodableStreamSerializer<T>(decoder: decoder, dataPreprocessor: preprocessor))
    }
}

extension DioRequest {
    @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
    fileprivate func withCheckedCancellationContinuation<T>(function: String = #function, _ body: (_Concurrency.CheckedContinuation<T, Never>) -> Void) async -> T {
        await withTaskCancellationHandler {
            await withCheckedContinuation(function: function, body)
        } onCancel: {
            cancel()
        }
    }
}
#endif
